/*
 *
 * Copyright (c) 2006 P.J.Leonard
 * 
 * http://www.frinika.com
 * 
 * This file is part of Frinika.
 * 
 * Frinika is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.

 * Frinika is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with Frinika; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package neuralmusic.brain.gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
//import java.awt.geom.Point2D;

import java.awt.Graphics2D;
import java.util.Random;

import javax.swing.JPanel;

import neuralmusic.brain.module.Brain;
import neuralmusic.brain.module.Connection;
import neuralmusic.brain.module.Excitable;
import neuralmusic.brain.module.Location;
import neuralmusic.brain.module.Module;
import neuralmusic.brain.module.Neuron;
import neuralmusic.brain.module.Point;

/**
 * 
 * @author pjl
 */
public class NetworkDisplayPanel extends JPanel {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private Image offScreenImage;
	private Dimension screenSize;
	private Graphics offScreenGraphics;

	private final Brain brain;
	private float minX;
	private float maxX;
	private float minY;
	private float maxY;
	Color colsPos[];
	Color colsNeg[];
	private int wid;
	private int height;

	static int nLevel = 256;

	// HashMap<Value, Point> map = new HashMap<Value, Point>();
	public NetworkDisplayPanel(Brain b) {
		super(true);
		this.brain = b;
		centre();
		colsPos = new Color[nLevel];
		colsNeg = new Color[nLevel];
		for (int i = 0; i < nLevel; i++) {
			int tt = (int) ((i * 256L) / nLevel);
			assert (tt >= 0);
			assert (tt < 256);

			colsNeg[i] = new Color(0, 0, 255, tt);
			colsPos[i] = new Color(255, 0, 0, tt);
			// colsNeg[i] = new Color(255, 0, 0, tt);
		}
	}

	void centre() {
		minX = Float.MAX_VALUE;
		maxX = Float.MIN_VALUE;
		minY = Float.MAX_VALUE;
		maxY = Float.MIN_VALUE;
		for (Module m : brain.getModules()) {

			for (Location n : m.getNeurons()) {
				Point p = n.getPoint();
				maxX = Math.max(p.x, maxX);
				maxY = Math.max(p.y, maxY);
				minX = Math.min(p.x, minX);
				minY = Math.min(p.y, minY);
			}
		}

	}

	static int rad = 8;
	static int border = 10;

	@Override
	public void paintComponent(Graphics g1) {
		super.paintComponent(g1);

		// System.out.println(" PAINT" );

		if (offScreenGraphics == null || !getSize().equals(screenSize)) {
			wid = getWidth() - 2 * border;
			height = getHeight() - 2 * border;
			screenSize = new Dimension(getSize());
			offScreenImage = createImage(getSize().width, getSize().height);
			offScreenGraphics = offScreenImage.getGraphics();
			paintOffScren();
		}

		Graphics2D g = (Graphics2D) g1;

		if (offScreenImage != null) {
			g.drawImage(offScreenImage, 0, 0, null);
		}
		// System.out.println("Painting");

		for (Module m : brain.getModules()) {

			for (Neuron n : m.getNeurons()) {

				Point p = map(n.getPoint());

				int x = (int) p.x; // border + (int) (wid * (p.x - minX) /
									// (maxX - minX));
				int y = (int) p.y; // border
				// + (int) (height * (p.y - minY) / (maxY - minY));

				float fval = (float) n.getDisplayValue();

				if (fval < 0) {
					int val = Math.min(nLevel - 1, (int) (-fval * nLevel));
					g.setColor(colsNeg[val]);
				} else {
					// System.out.print(val);
					int val = Math.min(nLevel - 1, (int) (fval * nLevel));
					// System.out.println(colsPos[val]);
					g.setColor(colsPos[val]);
				}

				g.fillRect(x, y, rad, rad);
				g.setColor(Color.BLACK);
				g.drawRect(x, y, rad, rad);

			}

		}
	}

	final Point map(Point p) {

		assert (p != null);
		final Point pt = new Point(0, 0);

		pt.x = border + (int) (wid * (p.x - minX) / (maxX - minX));
		pt.y = border + (int) (height * (p.y - minY) / (maxY - minY));
		return pt;
	}

	Random rand = new Random();

	private void paintOffScren() {

		offScreenGraphics.clearRect(0, 0, screenSize.width, screenSize.height);

		offScreenGraphics.setColor(Color.GRAY);

		for (Module m : brain.getModules()) {
			for (Neuron n : m.getNeurons()) {
				Color col = new Color(0.0f, rand.nextFloat(), rand.nextFloat(),
						0.4f);

				offScreenGraphics.setColor(col);
				Point p1 = map(n.getPoint()).clone();
				assert (p1 != null);
				for (Connection c : n.getOutCOnnections()) {
					Excitable sink = c.getSink();
					if (sink instanceof Location) {
						Point pt = ((Location) sink).getPoint();
						if (pt == null)
							continue;
						Point p2 = map(pt);
						assert (p2 != null);
						offScreenGraphics.drawLine((int) p1.x, (int) p1.y,
								(int) p2.x, (int) p2.y);
					}

				}

			}
		}
	}
}
